package net.comfycastle.musicplayer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.Bundle;
import android.provider.MediaStore.Audio;
import android.view.View;
import android.widget.ListView;

/**
 * 앨범들의 목록을 표현하는 Fragment
 * @author ricale
 *
 */
public class AlbumListFragment extends BaseListFragment {
	///////////
	//////////
	/////////   constant
	
	/** 객체 생성 당시 argument로 전달되는 bundle 객체에서 프래그먼트 아이디의 키값 */
	private static final String KEY_ID   = "FragAlbumList.keyId";
	/** 객체 생성 당시 argument로 전달되는 bundle 객체에서 앨범 종류(아티스트 or 앨범아티스트)의 키값 */
	private static final String KEY_KIND = "FragAlbumList.keyKind";
	/** 객체 생성 당시 argument로 전달되는 bundle 객체에서 앨범 세부 종류(아티스트/앨범아티스트 명)의 키값 */
	private static final String KEY_NAME = "FragAlbumList.keyName";
	
	/** 액티비티 제목 설정 시 필요한 문자열을 반환할 때 포함되는 문자열 상수 */
	private static final String FORTITLE_ARTIST = "아티스트: ";
	
	///////////
	//////////
	/////////   constructor
	
	/**
	 * FragAlbumList.newInstance("", "") 메소드를 호출한다.
	 * @param fragmentId 생성될 인스턴스의 고유 아이디
	 * @return FragAlbumList의 인스턴스
	 */
	public static AlbumListFragment newInstance(OBJECTID fragmentId) {
		return newInstance(fragmentId, "", "");
	} // end newInstance(FragmentId)
	
	/**
	 * FragAlbumList의 인스턴스를 생성/반환하는 정적 메소드
	 * 인자를 받지 못하는 Fragment 클래스 생성자 대신 인자를 받는다.
	 * @param fragmentId 생성될 인스턴스의 고유 아이디
	 * @param kind 앨범의 종류 (아티스트의 앨범인가 앨범아티스트의 앨범인가)
	 * @param name 앨범의 분류 (kind의 세부 분류)
	 * @return FragAlbumList의 인스턴스
	 */
	public static AlbumListFragment newInstance(OBJECTID fragmentId, String kind, String name) {
		AlbumListFragment instance = new AlbumListFragment();
		
		Bundle bundle = new Bundle();
		bundle.putString(KEY_ID,   fragmentId.name());
		bundle.putString(KEY_KIND, kind);
		bundle.putString(KEY_NAME, name);
		instance.setArguments(bundle);
		
		return instance;
	} // end newInstance(FragmentId, String, String)
	
	///////////
	//////////
	/////////   lifecycle callback method
	
	/**
	 * 프래그먼트가 파괴될 때의 콜백 메서드.
	 * 앨범 아트 비트맵 리소스를 해제한다.
	 */
	@Override
	public void onDestroy() {
		super.onDestroy();
		AlbumListMCAdapter adapter = (AlbumListMCAdapter)getListAdapter();
		adapter.releaseArts();
	} // end onDestroy
	
	///////////
	//////////
	/////////   getter
	
	/**
	 * 이 인스턴스의 고유 아이디를 리턴한다.
	 * @return 이 인스턴스의 고유 아이디
	 */
	public OBJECTID getFragmentId() {
		return OBJECTID.valueOf(getArguments().getString(KEY_ID));
	} // end getFragmentId
	
	/**
	 * 앨범의 종류를 얻는다.
	 * @return 앨범의 종류
	 */
	public String getKind() {
		return getArguments().getString(KEY_KIND);
	} // end getKind
	
	/**
	 * 앨범의 세부 분류를 얻는다.
	 * @return 앨범 종류의 세부 분류
	 */
	public String getName() {
		return getArguments().getString(KEY_NAME);
	} // end getName
	
	///////////
	//////////
	/////////   methods
	
	/**
	 * 프래그먼트를 포함하는 액티비티의 제목을 설정하기 위한 문자열을 반환하는 메서드.
	 * @return 제목으로 사용될 수 있는 문자열
	 */
	public String getTitleForWindow() {
		return FORTITLE_ARTIST + getName();
	} // end getTitleForWindow
	
	/**
	 * 생성 당시 입력 받은 분류 기준으로 앨범 목록을 만든다.
	 * BaseFragment(부모)의 onAttach에서 호출하기 때문에 따로 호출할 필요는 없다.
	 */
	protected void setList() {
		String kind = getKind();
		
		Cursor cursor;
		if(kind.equals("")) {
			cursor = getCursorGroupByAlbum();
		} else {
			cursor = getCursorGroupByAlbumKnownWhere();
		} // end if
	    
	    AlbumListMCAdapter adapter = new AlbumListMCAdapter(getActivity(), cursor);
	    if(kind.equals("")) {
	    	adapter.setViewState(AlbumListMCAdapter.VIEWSTATE.ALL);
	    } else {
			adapter.setViewState(AlbumListMCAdapter.VIEWSTATE.SPECIFY);
	    } // end if
	    
	    setListAdapter(adapter);
	} // end setList
	
	/**
	 * 모든 앨범의 리스트를 얻는다.
	 * @return 모든 앨범의 리스트를 가리키는 Cursor
	 */
	private Cursor getCursorGroupByAlbum() {
		String[] columns = new String[] { MPApp.TAG_ID, MPApp.TAG_ALBUM, MPApp.TAG_ALBUMARTIST, MPApp.TAG_ARTIST, MPApp.TAG_ALBUMID };
		Cursor   cursor  = getActivity().getContentResolver().query(Audio.Media.EXTERNAL_CONTENT_URI,
				                                               columns,
				                                               null,
				                                               null,
				                                               MPApp.TAG_ALBUM + "," + MPApp.TAG_ALBUMARTIST + "," + MPApp.TAG_ARTIST);
		
		List<Object[]> array  = new ArrayList<Object[]>();
		String[] currentGroup = new String[2];
		String[] lastGroup    = new String[2];
		
		while(cursor != null && cursor.moveToNext()) {
			currentGroup[0] = cursor.getString(cursor.getColumnIndex(MPApp.TAG_ALBUM));
			
			currentGroup[1] = cursor.getString(cursor.getColumnIndex(MPApp.TAG_ALBUMARTIST));
			if(currentGroup[1] == null || currentGroup[1].length() == 0) {
				currentGroup[1] = cursor.getString(cursor.getColumnIndex(MPApp.TAG_ARTIST));
			} // end if
			
			if(!currentGroup[0].equals(lastGroup[0]) || !currentGroup[1].equals(lastGroup[1])) {
				Object[] o = new String[columns.length + 1];
				for(int i = 0; i < columns.length; i++) {
					o[i] = cursor.getString(cursor.getColumnIndex(columns[i]));
				} // end for
				o[o.length - 1] = currentGroup[1];
				
				array.add(o);
				
				lastGroup[0] = currentGroup[0];
				lastGroup[1] = currentGroup[1];
			} // end if
		} // end while
		cursor.close();
		
		Collections.sort(array, new Comparator<Object[]>() {
			public int compare(Object[] lhs, Object[] rhs) {
				String lhss1 = (String)lhs[1];
				String rhss1 = (String)rhs[1];
				String lhss2 = (String)lhs[lhs.length - 1];
				String rhss2 = (String)rhs[rhs.length - 1];
				
				if(lhss1.compareTo(rhss1) != 0) {
					return lhss1.compareTo(rhss1);
				} else {
					return lhss2.compareTo(rhss2);
				} // end if
			} // end compare
		}); // end new Comparator<Object[]>()
		
		columns = new String[] {columns[0], columns[1], columns[2], columns[3], columns[4], MPApp.TAG_TITLEARTIST};
		MatrixCursor result = new MatrixCursor(columns);
		
		for(Object[] o : array) {
			result.addRow(o);
		} // end for
		
		return result;
	} // end getCursorGroupByAlbum
	
	/**
	 * 기준에 맞는 앨범명들로 구성된 Cursor를 얻는다.
	 * @return 특정 아티스트(mArtist)의 앨범명으로만 구성된 Cursor. 첫 항목은 앨범명이 아니라 (전체 곡 보기) 이다.
	 */
	private Cursor getCursorGroupByAlbumKnownWhere() {
		String[] columns = new String[] { MPApp.TAG_ID, MPApp.TAG_ALBUM, MPApp.TAG_ALBUMID };
		String   groupby = MPApp.TAG_ALBUM;
		Cursor   cursor  = getActivity().getContentResolver().query(Audio.Media.EXTERNAL_CONTENT_URI,
				                                      columns,
				                                      MusicUtility.makeWhere(getKind(), getName()),
				                                      null,
				                                      groupby);
		
		MatrixCursor result = new MatrixCursor(columns);
		result.addRow( new Object[] { 0, getString(R.string.list_item_all), 0 } );
		
		String currentGroup = null;
		String lastGroup    = null;
		
		while(cursor != null && cursor.moveToNext()) {
			currentGroup = cursor.getString(cursor.getColumnIndex(groupby));
			
			if(!currentGroup.equals(lastGroup)) {
				Object[] o = new Object[columns.length];
				
				for(int i = 1; i < columns.length; i++) {
					o[i] = cursor.getString(cursor.getColumnIndex(columns[i]));
				} // end for
				result.addRow(o);
				
				lastGroup = currentGroup;
			} // end if
		} // end while
		
		cursor.close();
		
		return result;
	} // end getCursorGroupByAlbumKnownWhere
	
	///////////
	//////////
	/////////   event listener & callback method
	
	/**
	 * 리스트가 클릭되었을 때의 콜백 메소드
	 */
	@Override
	public void onListItemClick(ListView l, View view, int position, long id) {
		BaseListFragment.OnListItemClickListener lintener = (BaseListFragment.OnListItemClickListener)getActivity();
		lintener.onItemClick(getFragmentId(), l, view, position, id);
	} // end onListItemClick
} // end FragAlbumList